/**
  ETFRoot project, Anyang Normal University && IMP-CAS
  \class ETFTrackTa
  \brief class for a target-zone track, specifically the track downstream of the
  reaction target
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-11-12
  \date 2021-12-09 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-11-12   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <iostream>
#include "ETFTrackTa4.h"
#include "ETFTrackTa.h"
#include "ETFMsg.h"
#include "ETFMath.h"
#include "ETFDCHit.h"

using std::cout;
using std::endl;

ClassImp(ETFTrackTa4);

ETFTrackTa4::ETFTrackTa4(){
  fPreTaTrk = new ETFTrackTa();
  fPostTaTrk = new ETFTrackTa();
} // end ctor

// copy ctor
ETFTrackTa4::ETFTrackTa4(const ETFTrackTa4 &t){
  *this = t;
} // end copy ctor
// assignment ctor
ETFTrackTa4 &ETFTrackTa4::operator=(const ETFTrackTa4 &t){
  if(&t == this) return *this;

  Copy(&t);

  return *this;
} // end member function operator=

// the same as copy ctor
void ETFTrackTa4::Copy(const ETFVTrack *t){
  ETFVTrack::Copy(t);

  const ETFTrackTa4 *p = dynamic_cast<const ETFTrackTa4 *>(t);
  fPreTaTrk = p->fPreTaTrk;
  fPostTaTrk = p->fPostTaTrk;
  fK3 = p->fK3; fB3 = p->fB3;
  fChi2 = p->fChi2;
  fDx2 = p->fDx2; fDxTa = p->fDxTa;
} // end member function Copy

// NOTE that we must assume a number for wire layers in the preTa-DCarray
// which currently is 4, of course. Yet for other values please derive this
// class and use your own value in it.
ETFDCHit *ETFTrackTa4::operator[](int layerId) const{
  static const int NL = 4; // N of X(Y) wire layers in the first DC array
  if(layerId < NL) return (*fPreTaTrk)[layerId];
  return (*fPostTaTrk)[layerId];
} // end member function operator

void ETFTrackTa4::AddHit(ETFDCHit *h){
  ETFMsg::Warn("ETFTrackTa4", "AddHit: not implemented. Please use the \
corresponding method of the consituent preTaTrk and postTaTrk");
} // end member function AddHit

map<int, ETFDCHit *> &ETFTrackTa4::GetHits(){
  ETFMsg::Warn("ETFTrackTa4", "GetHits: not implemented. Please use the \
corresponding method of the consituent preTaTrk and postTaTrk");
  return fHits; // never reach here, just to suppress compiler warnings
} // end member function GetHits

const map<int, ETFDCHit *> &ETFTrackTa4::GetHits() const{
  ETFMsg::Warn("ETFTrackTa4", "GetHits: not implemented. Please use the \
corresponding method of the consituent preTaTrk and postTaTrk");
  return fHits; // never reach here, just to suppress compiler warnings
} // end member functioin GetHits


ETFTrackTa4::~ETFTrackTa4(){
  if(fPreTaTrk) delete fPreTaTrk;
  if(fPostTaTrk) delete fPostTaTrk;
} // end dtor

int ETFTrackTa4::GetNofHits() const{
  return fPreTaTrk->GetNofHits() + fPostTaTrk->GetNofHits();
} // end member function GetNofHits

// number the track
void ETFTrackTa4::SetId(int id, short type){
  ETFVTrack::SetId(id, type);
  fPreTaTrk->SetId(id, type);
  fPostTaTrk->SetId(id, type);
} // end member function SetId

// user-input chiPD
void ETFTrackTa4::SetChiPD(double chiPD){
  fPreTaTrk->SetChiPD(chiPD);
  fPostTaTrk->SetChiPD(chiPD);
} // end member function SetChiPD

void ETFTrackTa4::Initialize(){
  ETFVTrack::Initialize();
  fPreTaTrk->Initialize();
  fPostTaTrk->Initialize();
  fK3 = -9999.; fB3 = -9999.;
  fChi2 = -9999.; fDx2 = -9999.; fDxTa = -9999.;
} // end member function Initialize

// set hit fired status for all hits
void ETFTrackTa4::SetHitFiredStatus(int s){
  fPreTaTrk->SetHitFiredStatus(s);
  fPostTaTrk->SetHitFiredStatus(s);
} // end member function SetHitFiredStatus

void ETFTrackTa4::SetHitPos(const string &d, double x) const{
  fPreTaTrk->SetHitPos(d, x);
  fPostTaTrk->SetHitPos(d, x);
} // end member function SetHitPos
/// assign hit pos at det's central plane
void ETFTrackTa4::UpdateHitPos(ETFDetector *det){
  fPreTaTrk->UpdateHitPos(det);
  fPostTaTrk->UpdateHitPos(det);
} // end member function UpdateHitPos
// update drift times for all member hits
void ETFTrackTa4::UpdateDriftTime(){
  fPreTaTrk->UpdateDriftTime();
  fPostTaTrk->UpdateDriftTime();
} // end member function UpdateDriftTime

// fit the track with drift distance info. Note that this is a united fit
// additional terms are added to chi2 to ameliorate the fitting
// \retval true: if the fitting result meets user criteria
bool ETFTrackTa4::Fit(){
  if(FitStatus::kUNFITTED != fFitStatus){
    if(FitStatus::kBADFIT == fFitStatus) return false;
    if(FitStatus::kGOODFIT == fFitStatus) return true;
  } // end if
  if(-9999. == fK3 || -9999. == fB3) ETFMsg::Error("ETFTrackTa4", "Fit: postMagTrk not assigned");

  // united fit with preTaTrk and postTaTrk, using postMagTrk info
  fChi2 = ETFMath::IterFit4Single(fPreTaTrk, fPostTaTrk, fK3, fB3, fDxTa, fDx2);
  UpdateChi();

  if(GoodFit()){ fFitStatus = FitStatus::kGOODFIT; return true; }
  fFitStatus = FitStatus::kBADFIT;
  return false;
} // end member function Fit

// update the hits' chis using the current (k, b)
void ETFTrackTa4::UpdateChi(){
  fPreTaTrk->UpdateChi();
  fPostTaTrk->UpdateChi();
} // end member function UpdateChi

int ETFTrackTa4::EnoughHit(){
  const int n0 = fPreTaTrk->EnoughHit(), n1 = fPostTaTrk->EnoughHit();
  if(!n0 || !n1) return 0;
  return n0 + n1;
} // end member function EnoughHit

bool ETFTrackTa4::GoodFit() const{
  // currently we don't apply threshold to chi2
  // since united tracking is only supposed to help solve left-right ambiguities
  return fPreTaTrk->GoodFit() && fPostTaTrk->GoodFit();
} // end member fucntion GoodFit

// draw the track as TGraph
void ETFTrackTa4::Draw(){
  fPreTaTrk->Draw();
  fPostTaTrk->Draw();
} // end member function Draw

// update fGraph in [z0, z1]
void ETFTrackTa4::ConstructGraph(double z0, double z1){
  fPreTaTrk->ConstructGraph(z0, z1);
  fPostTaTrk->ConstructGraph(z0, z1);
} // end member function ConstructGraph

void ETFTrackTa4::Print(){
  cout << "\033[34;1m________TrackTa4 ";
  cout << GetName() << " Print______________\033[0m" << endl;
  cout << "fK3: " << fK3 << " fB3: " << fB3 << endl;
  cout << "fChi2: " << fChi2 << " fDx2: " << fDx2 << " fDxTa: " << fDxTa << endl;
  fPreTaTrk->Print();
  fPostTaTrk->Print();
} // end member funtion Print
